package com.tian.service.impl;

import com.alibaba.fastjson.JSON;
import com.tian.common.CommonResult;
import com.tian.dto.coupon.CouponCacheDto;
import com.tian.entity.ChargeCoupon;
import com.tian.entity.ChargeUserCoupon;
import com.tian.entity.ChargeUserPoint;
import com.tian.enums.*;
import com.tian.mapper.ChargeCouponMapper;
import com.tian.mapper.ChargeUserCouponMapper;
import com.tian.mapper.ChargeUserPointMapper;
import com.tian.message.MessageReqIdPrefixConstant;
import com.tian.message.UserGetCouponAdditionalMessage;
import com.tian.message.UserGetCouponMessage;
import com.tian.producer.UserGetCouponAdditionalProducer;
import com.tian.service.UserGetCouponService;
import com.tian.util.ChargeMarketRedisKeyPrefix;
import com.tian.util.DateUtils;
import com.tian.util.RedisConstantPre;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RBucket;
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * {@code @description:} 用户领取优惠券服务实现类
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2024-08-19 9:11
 * {@code @version:} 1.0
 */
@Slf4j
@Service
public class UserGetCouponServiceImpl implements UserGetCouponService {
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ChargeUserPointMapper chargeUserPointMapper;
    @Resource
    private ChargeUserCouponMapper chargeUserCouponMapper;

    @Resource
    private ChargeCouponMapper chargeCouponMapper;


    @Resource
    private UserGetCouponAdditionalProducer userGetCouponAdditionalProducer;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void userGetCoupon(UserGetCouponMessage userGetCouponMessage) {
        RBucket<String> bucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.USER_GET_COUPON_MESSAGE_DUPLICATE_CONSUMER_KEY + userGetCouponMessage.getReqId());
        if (bucket.get() != null) {
            log.error("用户id:{}，优惠券id:{}，消息重复消费", userGetCouponMessage.getUserId(), userGetCouponMessage.getCouponId());
            return;
        }
        bucket.set(userGetCouponMessage.getReqId());
        bucket.expire(1, TimeUnit.DAYS);

        RBucket<String> couponBucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.CHARGE_COUPON_KEY + userGetCouponMessage.getCouponId());
        CouponCacheDto couponCacheDto = JSON.parseObject(couponBucket.get(), CouponCacheDto.class);
        int needPoint = 0;
        ChargeUserPoint chargeUserPoint = null;
        if (couponCacheDto.getSendType() == CouponSendTypeEnum.POINT.getSendType()) {
            needPoint = couponCacheDto.getPoint();
            chargeUserPoint = chargeUserPointMapper.selectByUserId(userGetCouponMessage.getUserId());
            int point = chargeUserPoint.getPoint() - chargeUserPoint.getFreeze();
            if (point < needPoint) {
                RList<Integer> list = redissonClient.getList(ChargeMarketRedisKeyPrefix.CHARGE_COUPON_STOCK_QUANTITY_KEY + userGetCouponMessage.getCouponId());
                list.add(userGetCouponMessage.getCouponId());
                log.error("用户id:{}，优惠券id:{}，不满足领取条件", userGetCouponMessage.getUserId(), userGetCouponMessage.getCouponId());
                return;
            }
            chargeUserPoint.setPoint(chargeUserPoint.getPoint() - needPoint);
        }


        Date expire;
        Date startTime = new Date();
        if (couponCacheDto.getValidityType() == 0) {
            Integer expireType = couponCacheDto.getExpire();
            Integer expireUnit = couponCacheDto.getExpireUnit();
            //计算到期时间
            LocalDate expireDate = ChargeCouponConditionExpireUnitEnum.calculateExpireDate(LocalDate.now(), expireUnit, expireType);
            if (expireDate == null) {
                log.error("用户id:{}，优惠券id:{}，优惠券过期时间计算失败", userGetCouponMessage.getUserId(), userGetCouponMessage.getCouponId());
                return;
            }
            expire = Date.from(Timestamp.valueOf(expireDate.atTime(LocalTime.MIDNIGHT)).toInstant());
        } else {
            expire = couponCacheDto.getValidityEndTime();
            startTime = couponCacheDto.getValidityStartTime();
        }

        ChargeUserCoupon chargeUserCoupon = new ChargeUserCoupon();
        chargeUserCoupon.setUserId(userGetCouponMessage.getUserId());
        chargeUserCoupon.setCouponId(userGetCouponMessage.getCouponId());
        chargeUserCoupon.setPeriod(expire);
        chargeUserCoupon.setStartTime(startTime);
        chargeUserCoupon.setStatus(UserCouponStatusEnum.INIT.getStatus());
        chargeUserCoupon.setCreateTime(new Date());

        if (chargeUserPoint != null) {
            int result = chargeUserPointMapper.updatePointByUserId(chargeUserPoint);
            if (result != 1) {
                log.error("用户id:{}，优惠券id:{}，更新用户积分失败", userGetCouponMessage.getUserId(), userGetCouponMessage.getCouponId());
                return;
            }
        }
        //用户真正领取到优惠券
        chargeUserCouponMapper.insert(chargeUserCoupon);

        //更新优惠券库存
        ChargeCoupon chargeCoupon = new ChargeCoupon();
        chargeCoupon.setId(userGetCouponMessage.getCouponId());
        chargeCoupon.setCount(couponCacheDto.getCount() - 1);
        chargeCouponMapper.updateByPrimaryKey(chargeCoupon);

        redissonClient.getAtomicLong(RedisConstantPre.COUPON_GET_COUNT_PRE + chargeUserCoupon.getCouponId()).incrementAndGet();

        redissonClient.getAtomicLong(ChargeMarketRedisKeyPrefix.USER_AVAILABLE_COUPON_COUNT_KEY + userGetCouponMessage.getUserId()).incrementAndGet();

        redissonClient.getAtomicLong(ChargeMarketRedisKeyPrefix.USER_GET_COUPON_TIMES_KEY + chargeUserCoupon.getUserId()+":"+chargeUserCoupon.getCouponId()).incrementAndGet();

        RAtomicLong userGetCouponTimesBucket = redissonClient.getAtomicLong(ChargeMarketRedisKeyPrefix.USER_SECONDS_KILL_COUPON_KEY + userGetCouponMessage.getUserId() + ":" + userGetCouponMessage.getCouponId());
        userGetCouponTimesBucket.incrementAndGet();

        log.info("用户id:{}，优惠券id:{}，成功领取优惠券", userGetCouponMessage.getUserId(), userGetCouponMessage.getCouponId());

        RBucket<Object> userPointBucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.USER_POINT_KEY + userGetCouponMessage.getCouponId());
        ChargeUserPoint chargeUserPointCache = JSON.parseObject(userPointBucket.get().toString(), ChargeUserPoint.class);
        chargeUserPointCache.setPoint(chargeUserPointCache.getPoint() - needPoint);
        userPointBucket.set(JSON.toJSONString(chargeUserPointCache));

        UserGetCouponAdditionalMessage userGetCouponAdditionalMessage = new UserGetCouponAdditionalMessage();
        userGetCouponAdditionalMessage.setUserCouponId(chargeUserCoupon.getId());
        userGetCouponAdditionalMessage.setUserId(userGetCouponMessage.getUserId());
        userGetCouponAdditionalMessage.setType(UserUpdatePointEnum.DEDUCT.getType());
        userGetCouponAdditionalMessage.setPoint(chargeUserPoint == null ? 0 : chargeUserPoint.getPoint());
        userGetCouponAdditionalMessage.setExpireDate(expire);
        userGetCouponAdditionalMessage.setModifyTime(new Date());
        userGetCouponAdditionalMessage.setReqId(MessageReqIdPrefixConstant.USER_GET_COUPON_ADDITIONAL_REQ_ID_PREFIX
                + UUID.randomUUID() + DateUtils.formatDefaultDateMs());
        userGetCouponAdditionalProducer.send(userGetCouponAdditionalMessage);
    }
}
